package pt.uma.gap.accessperm;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import pt.uma.gap.graph.ClassNode;
import pt.uma.gap.graph.GraphNode;
import pt.uma.gap.graph.GraphViz;
import pt.uma.gap.graph.MethodNode;
import pt.uma.gap.graph.PointeeEdge;
import pt.uma.gap.graph.ReadEdge;
import pt.uma.gap.graph.WriteEdge;

/**
 * Create DOT Language File from Class Structure
 * 
 * @author Duarte Abreu
 *
 */
public class DOTGraphTransformer {

	/**
	 * For each class and method create a DOT language file and SVG Image.
	 * 
	 * @param classNodeList
	 * @return
	 * @throws Exception
	 */
	public void transformeGraph(List<ClassNode> classNodeList)
			throws Exception {

		//Used to avoid duplication
		List<String> packageNameList = new ArrayList();
		
		for (ClassNode classNode : classNodeList) {

			GraphViz gvClass = new GraphViz();
			gvClass.addln0(gvClass.start_graph(classNode.getName()));

			gvClass.addln("rankdir=LR");
			
			//Node Package
			String packageName = classNode.getPackageName().replace('.', '_');
			if(!packageNameList.contains(packageName)){
				gvClass.addln(packageName + " [ label=\""
						+ classNode.getPackageName() + "\"]");
				packageNameList.add(packageName);
			}
			
			//Node Class
			String className = classNode.getFullName().replace('.', '_');
			gvClass.addln(className + " [ label=\""
					+ classNode.getName() + "\"]");
			
			//Edge From package node to class node
			gvClass.addln(packageName + " -> " + className);
			
			String classSVGFileName = classNode.getPackageName() + "."
					+ classNode.getName() + ".graph.svg";

			for (MethodNode methodNode : classNode.getMethodNodeList()) {
				try {

					String methodSVGFileName = classNode.getPackageName() + "."
							+ classNode.getName() + "."
							+ methodNode.getCompleteName() + ".graph.svg";

					File methodDOTFileName = new File(classNode.getPackageName()
							+ "." + classNode.getName() + "."
							+ methodNode.getCompleteName() + ".graph.dot");

					

					//Method node
					gvClass.addln(methodNode.getName()
							+ " [ fontcolor=blue, URL=\"" + methodSVGFileName
							+ "\" label=\"" + methodNode.getCompleteName()
							+ "\"]");

					//Edge from Class node to Method node
					gvClass.addln(className + " -> " + methodNode.getName());

					GraphViz gv = new GraphViz();
					gv.addln0(gv.start_graph(methodNode.getName()));

					StringBuilder stringBuilder = new StringBuilder("");
					for (GraphNode graphNode : methodNode.getGraphNodeRefList()) {
						stringBuilder.append(gv.sepace1()).append(
								graphNode.getName());
						if (graphNode.getOrigin().equals(
								GraphNode.NoteOrigin.FIELD)) {
							stringBuilder
									.append("[group=\"Ref\", color=darkviolet label=\""
											+ graphNode.getLabelExtended()
											+ "\"]");
						} else if (graphNode.getOrigin().equals(
								GraphNode.NoteOrigin.LOCAL)) {
							stringBuilder
									.append("[group=\"Ref\", color=brown label=\""
											+ graphNode.getLabelExtended()
											+ "\"]");
						} else if (graphNode.getOrigin().equals(
								GraphNode.NoteOrigin.PARAM)) {
							stringBuilder
									.append("[group=\"Ref\", color=darkorange label=\""
											+ graphNode.getLabelExtended()
											+ "\"]");
						}

						stringBuilder.append('\n');
					}
					gv.addln(stringBuilder.toString());

					StringBuilder cluster1 = new StringBuilder(
							gv.start_cluster("cluster_1"));

					cluster1.append(gv.sepace2()).append("center=true")
							.append('\n');
					cluster1.append(gv.sepace2())
							.append("node [style = filled]").append('\n');

					for (GraphNode graphNode : methodNode.getGraphNodeMemList()) {
						cluster1.append(gv.sepace2())
								.append(graphNode.getName())
								.append("[label=\"")
								.append(graphNode.getLabel()).append("\"]")
								.append('\n');
					}

					cluster1.append(gv.end_cluster());

					gv.addln(cluster1.toString());

					for (ReadEdge edge : methodNode.getReadEdgeList()) {
						if (edge.getFrom().getType()
								.equals(GraphNode.NodeType.FOO)) {
							gv.addln(edge.getTo().getName() + " -> "
									+ edge.getFrom().getName() + "[label = \""
									+ edge.getEdgeType()
									+ "\", dir=back, color=green]");

						} else {
							gv.addln(edge.getFrom().getName() + " -> "
									+ edge.getTo().getName() + "[label = \""
									+ edge.getEdgeType() + "\", color=green]");
						}
					}
					gv.addln();

					for (WriteEdge edge : methodNode.getWriteEdgeList()) {
						if (edge.getFrom().getType()
								.equals(GraphNode.NodeType.FOO)) {
							gv.addln(edge.getTo().getName() + " -> "
									+ edge.getFrom().getName() + "[label = \""
									+ edge.getEdgeType()
									+ "\", dir=back, color=red]");

						} else {
							gv.addln(edge.getFrom().getName() + " -> "
									+ edge.getTo().getName() + "[label = \""
									+ edge.getEdgeType() + "\", color=red]");
						}
					}
					gv.addln();

					for (PointeeEdge edge : methodNode.getPointeeEdgeList()) {
						gv.addln(edge.getFrom().getName() + " -> "
								+ edge.getTo().getName() + "[label = \""
								+ edge.getEdgeType() + "\", color=blue]");
					}

					gv.addln();

					gv.addln(methodNode.getFooNode().getName()
							+ " [shape=octagon];");
					gv.addln();
					gv.addln(methodNode.getContextNode().getName()
							+ " [shape=octagon];");

					gv.addln();

					gv.addln();

					gv.addln(classNode.getName()
							+ " [shape=plaintext, fontcolor=blue, URL=\""
							+ classSVGFileName + "\", label=\"Home "
							// + classNode.getPackageName()+ "."
							// +classNode.getName()
							+ "\" ]");
					gv.addln("{ rank=max; " + classNode.getName() + "; }");

					gv.addln0(gv.end_graph());

					gv.writeDotSourceToFile(gv.getDotSource(), methodDOTFileName);

					try {
						File methodSVGFile = new File(methodSVGFileName);
						
						gv.writeGraphToFile(gv.getGraph(gv.getDotSource()),
								methodSVGFile);
						
					} catch (Exception ex) {
						ex.printStackTrace();
					}

				} catch (IOException e) {
					e.printStackTrace();
				}

			}//For each method
			
			gvClass.addln0(gvClass.end_graph());

			File classDOTFile = new File(classNode.getPackageName() + "."
					+ classNode.getName() + ".graph.dot");

			gvClass.writeDotSourceToFile(gvClass.getDotSource(), classDOTFile);

			File classFileSVG = new File(classSVGFileName);
			try {
				gvClass.writeGraphToFile(
						gvClass.getGraph(gvClass.getDotSource()), classFileSVG);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			
		}//For each class

	}

}
